package com.thwcompany.service;

import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.io.UnsupportedEncodingException;
import java.util.UUID;

/**
 * Created by IntelliJ IDEA2021.3
 *
 * @Author: Tenghw
 * @Date: 2022/10/23  00:03
 * @Description: 生产者消息确认机制配置：发布者发布消息给交换机
 */
@SuppressWarnings("all")
@Slf4j
@Service
public class ProducerMessageConfimService implements RabbitTemplate.ConfirmCallback {
    private  RabbitTemplate rabbitTemplate;

    @Autowired
    public void setRabbitTemplate(RabbitTemplate rabbitTemplate) {
        this.rabbitTemplate = rabbitTemplate;
    }

    /**
     * 需要给ConfirmCallback赋值 不然不会走回调方法，默认是null
     */
    @PostConstruct
    public void init(){
        rabbitTemplate.setConfirmCallback(this);
    }


    //exchangeKey交换机名，routingkey路由键；message为发送的消息
    //new CorrelationData(id)主要是用来给发送的消息设置一个唯一id,交换机收到消息和唯一id,2次id一致，即证明是同一条消息
    public void sendMessage(String exchangeKey, String routingkey, String message) throws UnsupportedEncodingException {
        // 设置消息唯一标识
        String id= UUID.randomUUID().toString();
        CorrelationData correlationData = new CorrelationData(id);
        //需要给ConfirmCallback赋值 不然不会走回调方法，默认是null
        //rabbitTemplate.setConfirmCallback(this);
        rabbitTemplate.convertAndSend(exchangeKey,routingkey, message,correlationData);
        log.info("交换机名称：{}，routingkey名称：{}，生产者发送给的交换机的消息: {}，唯一ID：{}",
                exchangeKey,routingkey,message,correlationData.getId());
    }
    //public void sendMessage0(String exchangeKey, String routingkey, String message) throws UnsupportedEncodingException {
    //    MessageProperties messageProperties = new MessageProperties();
    //    // 设置消息唯一标识
    //    String messageId= UUID.randomUUID().toString();
    //    messageProperties.setMessageId(messageId);
    //    //设置消息持久化
    //    messageProperties.setDeliveryMode(MessageDeliveryMode.PERSISTENT);
    //    //消息类型
    //    messageProperties.setContentType("text/plain");
    //    //这条消息的过期时间，单位毫秒，过期后消息会被删除
    //    messageProperties.setExpiration("10000");
    //    //需要给ConfirmCallback赋值 不然不会走回调方法，默认是null
    //    //rabbitTemplate.setConfirmCallback(this);
    //    rabbitTemplate.convertAndSend("myExchange", "routingKey",  message,  messageProperties);
    //    log.info("交换机名称：{}，routingkey名称：{}，生产者发送给的交换机的消息: {}，唯一ID：{}",
    //            exchangeKey,routingkey,message,messageProperties.getMessageId());
    //}
    public void sendMessage1(String exchangeKey, String routingkey, String message) throws UnsupportedEncodingException {
        String messageId=UUID.randomUUID().toString();

        //封装消息的2种方式
        //方式1：
        //MessageProperties messageProperties = new MessageProperties();
        //messageProperties.setExpiration("10000");
        //messageProperties.setDeliveryMode(MessageDeliveryMode.PERSISTENT);
        //messageProperties.setMessageId(messageId);
        //Message message1 = new Message(message.getBytes("UTF-8"), messageProperties);
        //rabbitTemplate.convertAndSend("myExchange", "routingKey", message1,new CorrelationData(messageId));

        //方式2：构建消息体
        Message  message2=MessageBuilder.withBody(message.getBytes())
                .setMessageId(messageId)// 设置消息唯一标识
                .setContentType(MessageProperties.CONTENT_TYPE_TEXT_PLAIN)//消息类型
                .setDeliveryMode(MessageDeliveryMode.PERSISTENT)//设置消息持久化
                .setContentEncoding("UTF-8")//消息编码
                .setExpiration("10000")//这条消息的过期时间，单位毫秒，过期后消息会被删除
                .setPriority(5)//优先级
                .setUserId("root")
                .build();

        //需要给ConfirmCallback赋值 不然不会走回调方法，默认是null
        //rabbitTemplate.setConfirmCallback(this);

        CorrelationData correlationData = new CorrelationData(messageId);
        rabbitTemplate.convertAndSend("myExchange", "routingKey", message2,correlationData);
        log.info("交换机名称：{}，routingkey名称：{}，生产者发送给的交换机的消息: {}，唯一ID：{}",
                exchangeKey,routingkey,message,message2.getMessageProperties().getMessageId());
    }

    /**
     * 此方法用于监听消息是否发送到交换机
     * @param correlationData: 对象内部只有一个 id 属性，用来标识当前消息的唯一性
     * @param ack: 当交换机存在时为true，否则为false；
     * @param cause: 发布者发布消息给交换机：若失败，cause为失败原因；若成功，cause=null
     */
    @Override
    public void confirm(CorrelationData correlationData, boolean ack, String cause) {
        String id= correlationData==null? "无": correlationData.getId();
        if(ack){
            log.info("消息成功发送到交换机");
            log.info("生产者消息推送给的交换机的状态:{}, 唯一ID：:{}",ack,id);
        }else {
            log.info("消息发送到交换机失败");
            log.info("生产者消息推送给的交换机的状态:{}, 唯一ID：:{},错误原因cause ：{}",ack,id,cause);
        }
    }
}
